In [ ]:
import numpy as np
import pandas as pd
%matplotlib inline
import math 
from xgboost.sklearn import XGBClassifier
from sklearn.cross_validation import cross_val_score
from sklearn import cross_validation
from sklearn.metrics import roc_auc_score
from matplotlib import pyplot
import seaborn
from sklearn.cross_validation import train_test_split
import xgboost as xgb

In [ ]:
train = pd.read_csv('train.csv', delimiter= "|")
test = pd.read_csv('test.csv', delimiter= "|")
target = pd.read_csv('target_train.csv', delimiter= "|")

In [ ]:
train.head()

In [ ]:
print train.columns, train.shape

In [ ]:
# общая статистика
train.describe()

In [ ]:
target.describe()
Пo данным можно сделать вывод, что это транзакции в разных торговых точках merchant с определенной датой, суммой транзакции, mcc кодом терминала, кодом договора(term_id?) и идентификатором пользователя, и набором анонимных признаков.

In [ ]:
test.describe()

In [ ]:
# В начале потенциально id торговой точки, пользователя и term должны оказаться лишними признаками
# Интересно увидеть сумму транзакций по топ т.точкам, пользователям и mcc кодам

In [ ]:
for column in train:
    print column, ": ", len(train[column].unique())

In [ ]:
# По колву уникальных значений получаем и фактическим значениям получаем вещественные, целочисленные и категориальные признаки
real_features = ["sum", "date", "f18"]
discrete_features = ["merchant", "term_id", "user_id"]
cat_features = ["mcc", "f1", "f2", "f4","f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14","f15","f16", "f17"]

In [ ]:
# Имеем более менее равномерное распределение по кол-ву транзакций в разрезе т.точек на трейне 
#(взят логарифм, чтобы сгладить пик)
print "кол-во уникальных т.точек", len(train.merchant.value_counts())
np.log(train.merchant.value_counts().head(50)).plot(kind = 'bar', figsize=(10, 5))

In [ ]:
# распределение для теста совпадает для трейна (взят логарифм, чтобы сгладить пик)
print "кол-во уникальных т.точек", len(test.merchant.value_counts())
np.log(test.merchant.value_counts().head(50)).plot(kind = 'bar', figsize=(10, 5))

In [ ]:
#Аналогично для mcc
print "кол-во уникальных т.точек", len(train.mcc.value_counts())
train.mcc.value_counts().head(50).plot(kind = 'bar', figsize=(10, 5))

In [ ]:
#Аналогично для mcc, распределения совпадают
print "кол-во уникальных mcc", len(test.mcc.value_counts())
test.mcc.value_counts().head(50).plot(kind = 'bar', figsize=(10, 5))

In [ ]:
# гистограммы можно строить сразу по нескольким признакам, за исключением пару выбросов, имеем более мене равномерное распределение
train[discrete_features].plot.hist(bins = 100, figsize=(20, 20))
test[discrete_features].plot.hist(bins = 100, figsize=(20, 20))

In [ ]:
# для категориальных признаков, кроме mcc.
# Гистограммы для теста и трейна совпадают
train[["f1", "f2", "f4","f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14","f15","f16", "f17"]].plot.hist(bins = 100, figsize=(20, 20))
test[["f1", "f2", "f4","f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14","f15","f16", "f17"]].plot.hist(bins = 100, figsize=(20, 20))

In [ ]:
train['target'] = target

In [ ]:
#Построим scatterplot для пар вещественных признаков
import seaborn
seaborn.pairplot(train[real_features+ ["target"]], hue="target", diag_kind="kde")

# по результатом видно, что таргет 1 чаще при более крупных сумме.

In [ ]:
# аналогично для категориальных признаков, для первых 10к значений 
seaborn.pairplot(train[cat_features + ["target"]].head(10000), hue="target", diag_kind="kde")
# признаков много, но можно выявить интересные закономерности. Оставим для более глубого анализа

In [ ]:
# аналогично для дискретных признаков, для первых 10к значений 
seaborn.pairplot(train[discrete_features + ["target"]].head(10000), hue="target", diag_kind="kde")
# эти три признака на первый взгляд не влияют на отклик, генерацию признаков отложим до первого безлайна

In [ ]:
# построим матрицу корреляций не категориальных признаков
seaborn.heatmap(train[discrete_features+real_features].corr(), square=True)

#значимой коррелации, кроме как т.точки и term_id (договор)

In [ ]:
train.date.head(5)

In [ ]:
# поиграемсяс датой, добавим день месяц и тд
train = pd.read_csv('train.csv', delimiter= "|")
test = pd.read_csv('test.csv', delimiter= "|")
target = pd.read_csv('target_train.csv', delimiter= "|")

def fix_date_time(df):
    def extract_field(_df, start, stop):
        return _df['date'].map(lambda dt: int(dt[start:stop]))
    df['Year'] = extract_field(df,0,4)
    df['Month'] = extract_field(df,5,7)
    df['Day'] = extract_field(df,8,10)
    df['Hour'] = extract_field(df,11,13)
    df['Minute'] = extract_field(df,14,16)
    
    return df.drop(['date'], axis = 1)

train = fix_date_time(train)
test = fix_date_time(test)

In [ ]:
print train.Year.unique(), test.Year.unique()
# диапозоны дат у данных пересекающиеся, так что

In [ ]:
from sklearn.cross_validation import train_test_split
X_fit, X_eval, y_fit, y_eval= train_test_split(
    train, target, test_size=0.20, random_state=1
)

In [ ]:
#обучим первую модель. Логистическую регрессию, поварьируем регуляризацию
from sklearn.linear_model import LogisticRegression
from sklearn import cross_validation
from sklearn.metrics import roc_auc_score
from sklearn import grid_search

lr = LogisticRegression()

CVscores = cross_validation.cross_val_score(lr, X_fit, y_fit.target, scoring='roc_auc', cv=5)

#поварьируем регуляризацию
Cs = 10**np.linspace(-4, 4, num=10)
grid = {'C': Cs}
gridsearch = grid_search.GridSearchCV(lr, grid, scoring='roc_auc', cv=5)
gridsearch.fit(X_fit, y_fit.target)
gridscores = [-x.mean_validation_score for x in gridsearch.grid_scores_]

C = Cs[np.argmin(gridscores)]

# обучим модель с полученными параметрами
lrCV = LogisticRegression(C=C)
lrCV.fit(X_fit, y_fit)

In [ ]:
auc_train = roc_auc_score(y_fit.target, lrCV.predict(X_fit))
auc_val = roc_auc_score(y_eval.target, lrCV.predict(X_eval))

print 'auc_train: ', auc_train
print 'auc_val: ', auc_val

In [ ]:
# результаты получиcь достаточно плохие, если в таргете среднее значение результатов 0,47, то тут 0,06  - модель сильно переобучилась в сторону 0
print np.mean(lrCV.predict(X_fit)), target.mean(), np.mean(y_fit.target)

In [ ]:
#Применим xgboost, он должен показать хорошие первоначальные результаты за счет того что 
# отлично борется c переобучением
# Разделим данные на обучающую, валидационную и тестовую выборку. Данные достаточно много, это имеет смысл сделать 
import xgboost as xgb
clf = xgb.XGBClassifier(missing=np.nan, max_depth=3, 
                        n_estimators=750, learning_rate=0.01, gamma =0.3, min_child_weight = 3,
                        subsample=0.9, colsample_bytree=0.8, seed=2000,objective= 'binary:logistic')

clf.fit(X_fit, y_fit, early_stopping_rounds=40,  eval_metric="auc", eval_set=[(X_eval, y_eval)])

In [ ]:
auc_train = roc_auc_score(y_fit.target, clf.predict(X_fit))
auc_val = roc_auc_score(y_eval.target, clf.predict(X_eval))

print 'auc_train: ', auc_train
print 'auc_val: ', auc_val

In [ ]:
print np.mean(clf.predict(X_fit)), target.mean(), np.mean(y_fit.target)
# значения стало лучше AUC чуть меньше 0,6

In [ ]:
# расмотрим какие признаки модель посчитала важными
def get_xgb_imp(xgb, feat_names):
    from numpy import array
    imp_vals = xgb.booster().get_fscore()
    imp_dict = {feat_names[i]:float(imp_vals.get('f'+str(i),0.)) for i in range(len(feat_names))}
    total = array(imp_dict.values()).sum()
    return {k:v/total for k,v in imp_dict.items()}

get_xgb_imp(clf,X_fit.columns)

In [ ]:
# необычно, юзер id - оказался сильно значимым признаком.
# огорчает, что неизвестно на момент решения задачи что именно классиф.
train = train.drop(['f14', 'f15'],axis=1)
test = test.drop(['f14', 'f15'],axis=1)

In [ ]:
# добавим частоту транзакций к mcc коду

mcc_con = pd.concat([test['mcc'], train['mcc']])
values = dict(mcc_con.value_counts())

train['_mcc_freq'] = train['mcc'].map(values)
test['_mcc_freq'] = test['mcc'].map(values)

train['_mcc_freq'] = train['_mcc_freq'].fillna(-1)
test['_mcc_freq'] = test['_mcc_freq'].fillna(-1)

print train.head()
print(train.info())

In [ ]:
# обучим модель еще раз
X_fit, X_eval, y_fit, y_eval= train_test_split(
    train, target, test_size=0.20, random_state=1
)

clf = xgb.XGBClassifier(missing=np.nan, max_depth=3, 
                        n_estimators=750, learning_rate=0.01, gamma =0.3, min_child_weight = 3,
                        subsample=0.9, colsample_bytree=0.8, seed=2000,objective= 'binary:logistic')

clf.fit(X_fit, y_fit, early_stopping_rounds=40,  eval_metric="auc", eval_set=[(X_eval, y_eval)])
auc_train = roc_auc_score(y_fit.target, clf.predict(X_fit))
auc_val = roc_auc_score(y_eval.target, clf.predict(X_eval))

print 'auc_train: ', auc_train
print 'auc_val: ', auc_val

In [ ]:
# результаты несколько улучшились
get_xgb_imp(clf,X_fit.columns)

In [ ]:
# новый признак не привнес нового в модель, дропнем его, но попробуем заменить частотами три айдишника, кроме mcc
# при этом сами id дропнуть


term_con = pd.concat([test['term_id'], train['term_id']])
values = dict(term_con.value_counts())

train['_term_freq'] = train['term_id'].map(values)
test['_term_freq'] = test['term_id'].map(values)


mer_con = pd.concat([test['merchant'], train['merchant']])
values = dict(mer_con.value_counts())

train['_merchant_freq'] = train['merchant'].map(values)
test['_merchant_freq'] = test['merchant'].map(values)

user_con = pd.concat([test['user_id'], train['user_id']])
values = dict(mer_con.value_counts())

train['_user_freq'] = train['merchant'].map(values)
test['_user_freq'] = test['merchant'].map(values)


#дропнем так же незначимые признаки
train = train.drop(['Minute', 'Year', 'f11', 'f12', 'f13', 'f16', 'f17', 'f7', 'f8'],axis=1) 
test = test.drop(['Minute', 'Year', 'f11', 'f12', 'f13', 'f16', 'f17', 'f7', 'f8'],axis=1)

train = train.drop(['merchant', 'user_id', 'term_id'],axis=1)
test = test.drop(['merchant', 'term_id', 'user_id'],axis=1)

In [ ]:
X_fit, X_eval, y_fit, y_eval= train_test_split(
    train, target, test_size=0.20, random_state=1
)
clf = xgb.XGBClassifier(missing=np.nan, max_depth=3, 
                        n_estimators=1300, learning_rate=0.02, gamma =0.3, min_child_weight = 3,
                        subsample=0.9, colsample_bytree=0.8, seed=2000,objective= 'binary:logistic')

clf.fit(X_fit, y_fit, early_stopping_rounds=50,  eval_metric="auc", eval_set=[(X_eval, y_eval)])
auc_train = roc_auc_score(y_fit.target, clf.predict(X_fit))
auc_val = roc_auc_score(y_eval.target, clf.predict(X_eval))

print 'auc_train: ', auc_train
print 'auc_val: ', auc_val

In [ ]:
test_target = clf.predict(test)
submission = pd.DataFrame(test_target)
submission.to_csv("test_target.csv", index=False)

In [ ]: